/*******************************************************************************
 * Copyright (c) 2001, 2002 Boris Pruessmann and others. All rights reserved.
 * This program and the accompanying materials are made available under the
 * terms of the Common Public License v0.5 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors: Boris Pruessmann - Initial implementation.
 ******************************************************************************/
package net.sourceforge.perforce.ui.dialogs;

import net.sourceforge.perforce.api.internal.Spec;
import net.sourceforge.perforce.api.internal.SpecData;
import net.sourceforge.perforce.core.PerforceException;
import net.sourceforge.perforce.core.api.IChangeResult;
import net.sourceforge.perforce.core.api.IPerforceServer;
import net.sourceforge.perforce.core.internal.api.ChangeSpec;
import net.sourceforge.perforce.core.resources.IChangelist;
import net.sourceforge.perforce.ui.internal.Policy;

import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;

/**
 * @version $Revision: 488 $
 * @author <a href="mailto:bpruessmann@users.sourceforge.net">Boris
 *         Pruessmann</a>
 */
public class ChangeSpecDialog extends AbstractChangeSpecDialog {

  private static final String NO_DESCRIPTION = "<enter description here>";
  /** Stores the text for the ok button. */
  private String okButtonText;

  /** Holds the Spec object. */
  private Spec spec;

  /** Holds the SpecData object. */
  private SpecData specData;

  private String description = "";

  /**
   * Creates a new ChangeSpecDialog for the given server.
   * 
   * @param parentShell the parent shell
   * @param server the perforce server.
   * @return the new ChangeSpecDialog
   * 
   * @throws PerforceException in case of an error.
   */
  public static final ChangeSpecDialog newInstance(Shell parentShell, IPerforceServer server)
      throws PerforceException {
    ChangeSpecDialog result = new ChangeSpecDialog(parentShell);
    result.okButtonText = Policy.bind("ChangeSpecDialog.okButtonTextUpdate"); //$NON-NLS-1$

    IChangeResult changeResult = server.change((Integer) null);
    result.specData = changeResult.getChangeSpecData();
    result.spec = changeResult.getChangeSpecDefinition();

    return result;
  }

  /**
   * Creates a new ChangeSpecDialog for the given changelist.
   * 
   * @param parentShell the parent shell
   * @param changelist the changelist
   * @param okButtonText text for the ok button
   * @return the new ChangeSpecDialog
   * 
   * @throws PerforceException in case of an error.
   */
  public static final ChangeSpecDialog newInstance(Shell parentShell, IChangelist changelist,
      String okButtonText) throws PerforceException {
    ChangeSpecDialog result = new ChangeSpecDialog(parentShell);

    IChangeResult changeResult = changelist.getServer().change(changelist.getId());

    result.specData = changeResult.getChangeSpecData();
    result.spec = changeResult.getChangeSpecDefinition();
    if (result.getDescription().equals(NO_DESCRIPTION))
      result.setDescription(changelist.getDescription());
    result.okButtonText = okButtonText;

    return result;
  }

  /** @see org.eclipse.jface.dialogs.Dialog#Dialog(org.eclipse.swt.widgets.Shell) */
  ChangeSpecDialog(Shell parentShell) {
    super(parentShell);
  }

  /**
   * Retrieves the complete ChangeSpec that represents the dialog's input.
   * 
   * @return the changespec.
   */
  public ChangeSpec getChangeSpec() {
    return new ChangeSpec(spec.format(specData), getFiles());
  }

  @Override
  protected Control createButtonBar(Composite parent) {
    Control result = super.createButtonBar(parent);
    if (okButtonText != null) {
      getButton(IDialogConstants.OK_ID).setText(okButtonText);
    }

    String description = getDescriptionText();
    if (description.equals(NO_DESCRIPTION)) //$NON-NLS-1$
    {
      getButton(IDialogConstants.OK_ID).setEnabled(false);
    } else {
      getButton(IDialogConstants.OK_ID).setEnabled(true);
    }

    return result;
  }

  @Override
  protected void createTableButtonBar(Composite parent, final TableViewer viewer) {
    Composite composite = new Composite(parent, SWT.NULL);
    composite.setFont(parent.getFont());

    GridLayout layout = new GridLayout();
    layout.numColumns = 3;
    layout.makeColumnsEqualWidth = true;
    composite.setLayout(layout);

    GridData data = new GridData(GridData.HORIZONTAL_ALIGN_END | GridData.VERTICAL_ALIGN_CENTER);
    composite.setLayoutData(data);

    Button invertSelectionButton = new Button(composite, SWT.PUSH);
    invertSelectionButton.setFont(composite.getFont());
    invertSelectionButton.setText(Policy.bind("ChangeSpecDialog.invertSelection")); //$NON-NLS-1$
    setTableButtonLayoutData(invertSelectionButton);
    invertSelectionButton.addSelectionListener(new SelectionAdapter() {
      @Override
      public void widgetSelected(SelectionEvent event) {
        TableItem[] items = viewer.getTable().getItems();
        for (int i = 0, length = items.length; i < length; i++) {
          boolean selection = items[i].getChecked();
          items[i].setChecked(!selection);
        }
      }
    });

    Button selectAllButton = new Button(composite, SWT.PUSH);
    selectAllButton.setFont(composite.getFont());
    selectAllButton.setText(Policy.bind("ChangeSpecDialog.selectAll")); //$NON-NLS-1$
    setTableButtonLayoutData(selectAllButton);
    selectAllButton.addSelectionListener(new SelectionAdapter() {
      @Override
      public void widgetSelected(SelectionEvent event) {
        boolean selection = true;
        changeTableSelection(viewer, selection);
      }
    });

    Button deselectAllButton = new Button(composite, SWT.PUSH);
    deselectAllButton.setFont(composite.getFont());
    deselectAllButton.setText(Policy.bind("ChangeSpecDialog.deselectAll")); //$NON-NLS-1$
    setTableButtonLayoutData(deselectAllButton);
    deselectAllButton.addSelectionListener(new SelectionAdapter() {
      @Override
      public void widgetSelected(SelectionEvent event) {
        boolean selection = false;
        changeTableSelection(viewer, selection);
      }
    });
  }

  @Override
  protected void okPressed() {
    specData.replace("Description", getDescriptionText()); //$NON-NLS-1$

    specData.replace("Files", getSelectedFiles(), getFileCount());
    specData.replace("Jobs", getSelectedJobs(), getJobCount());
    super.okPressed();
  }

  @Override
  protected Text createDescriptionTextControl(Composite composite, int style) {
    return super.createDescriptionTextControl(composite, style);
  }

  @Override
  String getTitle() {
    return Policy.bind("ChangeSpecDialog.dialogTitle"); // NON-NLS-1$
  }

  @Override
  public String getDescription() {
    if (description.length() > 0) return description;
    return specData.get("Description").trim(); //$NON-NLS-1$
  }

  @Override
  String getChangelist() {
    return specData.get("Change"); //$NON-NLS-1$
  }

  @Override
  String getDate() {
    return specData.get("Date"); //$NON-NLS-1$
  }

  @Override
  String getClientName() {
    return specData.get("Client"); //$NON-NLS-1$
  }

  @Override
  String getUserName() {
    return specData.get("User"); //$NON-NLS-1$
  }

  @Override
  String getStatus() {
    return specData.get("Status"); //$NON-NLS-1$
  }

  @Override
  String[] getFiles() {
    return specData.getArray("Files");
  }

  @Override
  protected String[] getJobs() {
    return specData.getArray("Jobs");
  }

  /**
   * Sets the LayoutData for the given 'Table' Button.
   * 
   * @param button the button
   */
  private void setTableButtonLayoutData(Button button) {
    GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
    data.heightHint = convertVerticalDLUsToPixels(IDialogConstants.BUTTON_HEIGHT);
    int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
    data.widthHint = Math.max(widthHint, button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x);
    button.setLayoutData(data);
  }

  /**
   * Changes the selection state of all files to the given value.
   * 
   * @param selection new selection value.
   */
  private void changeTableSelection(TableViewer viewer, boolean selection) {
    TableItem[] items = viewer.getTable().getItems();
    for (int i = 0, length = items.length; i < length; i++) {
      items[i].setChecked(selection);
    }
  }

  private void setDescription(String description) {
    this.description = description;
  }

}
